

#include "evaluate.h"
#include <ctime>

int gridUnit;
int x_gridNum;
int y_gridNum;
int numBins;
ckt this_ckt;
double HPWL, penalty, displacement, max_displacement, targUt;
string directory;
vector<double> util_array;

int main(int argc, char ** argv)
{
	if(argc != 6)
	{
		cout << "Incorrect arguments. existing .."<<endl;
		cout << "Usage : walle [.aux] [.legal] [target_util] [initial .pl] [max_displacement]\n" <<endl;
		return 1;
	}
	  cout << "===============================================================" <<endl;
		cout << "                    PKU  Walle                             " <<endl;
		cout << "				 										    " <<endl;
	  cout << "===============================================================" <<endl;

	max_displacement = atof(argv[5]) * 0.95;
	double original_targUt = atof(argv[3]);
	targUt = original_targUt * 0.98;
	string legalname = argv[2];

	/* Preparation Stage */
	read_bookshelf(this_ckt, argc, argv);
	/* Calculate the extreme points of each net */
	initialize_net(this_ckt);

	/* If the displacement limit is large */
	if(max_displacement >= 1000)
	{
		int original_HPWL;

		/* Must-do Stages */
		{
			util_array.resize(numBins);
			util_array_setup(this_ckt, util_array);
		    reduce_density_1(this_ckt, 0.98, 0.90, -30);

			util_array.clear();
			util_array.resize(numBins);
			util_array_setup(this_ckt, util_array);
		    reduce_density_1(this_ckt, 0.98, 0.94, -20);

			util_array.clear();
			util_array.resize(numBins);
			util_array_setup(this_ckt, util_array);
		    reduce_density_1(this_ckt, 0.98, 0.96, -10);

			util_array.clear();
			util_array.resize(numBins);
			util_array_setup(this_ckt, util_array);
		    reduce_density_1(this_ckt, 0.98, 0.96, 0);

			util_array.clear();
			util_array.resize(numBins);
			util_array_setup(this_ckt, util_array);
		    reduce_density_2(this_ckt, 0.96, 0.92, 300);
			   
			util_array.clear();
			util_array.resize(numBins);
			util_array_setup(this_ckt, util_array);		
		    reduce_density_2(this_ckt, 0.96, 0.94, 600);
		    
		    HPWL = measure_HPWL(this_ckt);
		    original_HPWL = HPWL;

			util_array.clear();
			util_array.resize(numBins);
			util_array_setup(this_ckt, util_array);
		    bin_manipulation_1(this_ckt); 
		    
		  
			util_array.clear();
			util_array.resize(numBins);
			util_array_setup(this_ckt, util_array);			
		    bin_manipulation_2(this_ckt); 

			util_array.clear();
			util_array.resize(numBins);
			util_array_setup(this_ckt, util_array);				
		    reduce_density_1(this_ckt, 0.98, 0.96, -10);
		    
			util_array.clear();
			util_array.resize(numBins);
			util_array_setup(this_ckt, util_array);
		    reduce_density_1(this_ckt, 0.98, 0.96, 0);
		    HPWL = measure_HPWL(this_ckt);    	
		}

		cout << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl << endl;
		cout <<  "Optional Stages" << endl << endl;
		cout << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl << endl;

		/* Optional Stages */
		{
			/* Self-Adaptive HPWL Reduction */
			while(HPWL < original_HPWL * 0.995)
			{
				original_HPWL = HPWL;

				util_array.clear();
				util_array.resize(numBins);
				util_array_setup(this_ckt, util_array);
			    bin_manipulation_1(this_ckt); 		  
			   
	    		util_array.clear();
				util_array.resize(numBins);
				util_array_setup(this_ckt, util_array);
			    bin_manipulation_2(this_ckt); 
			   
	   			util_array.clear();
				util_array.resize(numBins);
				util_array_setup(this_ckt, util_array);		
			    reduce_density_1(this_ckt, 0.98, 0.96, 0);
			    HPWL = measure_HPWL(this_ckt);
			}

			int cnt = 7;
			penalty = measure_ABU(this_ckt, BIN_DIM, original_targUt);
			while(penalty > 0.005 && cnt > 0)
			{	
				util_array.clear();
				util_array.resize(numBins);
				util_array_setup(this_ckt, util_array);
			    reduce_density_1(this_ckt, 0.98, 0.95, (5 - cnt) * 10);
			    penalty = measure_ABU(this_ckt, BIN_DIM, original_targUt);
			    cnt--;
			}

			cnt = 10;
			while(penalty > 1e-3 && cnt > 0)
			{ 	
				util_array.clear();
				util_array.resize(numBins);
				util_array_setup(this_ckt, util_array);
			    reduce_density_2(this_ckt, 0.98, 0.97, (10 - cnt) * 50);
			    penalty = measure_ABU(this_ckt, BIN_DIM, original_targUt);
			    cnt--;
			}
			    
			cnt = 3;
			while(penalty > 1e-4 && cnt > 0)
			{
				util_array.clear();
				util_array.resize(numBins);
				util_array_setup(this_ckt, util_array);	
			    reduce_density_3(this_ckt, 0.96, 0.96, (3 - cnt) * 300);
			    penalty = measure_ABU(this_ckt, BIN_DIM, original_targUt);
			    cnt--;
			}
		}	
	}
	else // If the displacement limit is small
	{
	    int cnt = 10;
	    while(penalty > 0.001 && cnt > 0)
	    {
	    	util_array.clear();
			util_array.resize(numBins);
			util_array_setup(this_ckt, util_array);
			reduce_density_check(this_ckt, 0.98, 0.95, -100);
			//HPWL = measure_HPWL(this_ckt);
			penalty = measure_ABU(this_ckt, BIN_DIM, original_targUt);
			//displacement = measure_displacement(this_ckt, legalname.c_str());
	    	cnt--;
	    }

		util_array.clear();
		util_array.resize(numBins);
		util_array_setup(this_ckt, util_array);		
	    bin_manipulation_check(this_ckt);
	    //HPWL = measure_HPWL(this_ckt);
	    penalty = measure_ABU(this_ckt, BIN_DIM, original_targUt);
	    //displacement = measure_displacement(this_ckt, legalname.c_str());

	    cnt = 5;
	    while(penalty > 0.001 && cnt > 0)
	    {
	    	util_array.clear();
			util_array.resize(numBins);
			util_array_setup(this_ckt, util_array);
			reduce_density_check(this_ckt, 0.98, 0.95, -100);
			//HPWL = measure_HPWL(this_ckt);
			penalty = measure_ABU(this_ckt, BIN_DIM, original_targUt);
			//displacement = measure_displacement(this_ckt, legalname.c_str());
	    	cnt--;
	    }
	    
		util_array.clear();
		util_array.resize(numBins);
		util_array_setup(this_ckt, util_array);
	    bin_manipulation_check(this_ckt);
	    //HPWL = measure_HPWL(this_ckt);
	    penalty = measure_ABU(this_ckt, BIN_DIM, original_targUt);
	    //displacement = measure_displacement(this_ckt, legalname.c_str());
	    
	    cnt = 10;
	    while(penalty > 1e-4 && cnt > 0)
	    {
	    	util_array.clear();
			util_array.resize(numBins);
			util_array_setup(this_ckt, util_array);
			reduce_density_check(this_ckt, 0.98, 0.95, (7 - cnt) * 100);
	    	//HPWL = measure_HPWL(this_ckt);
	    	penalty = measure_ABU(this_ckt, BIN_DIM, original_targUt);
	    	//displacement = measure_displacement(this_ckt, legalname.c_str());
	    	cnt--;
	    }
	}

	/* Safety Check Stage */
	
	displacement = measure_displacement(this_ckt, legalname.c_str());
	// Some function to do that...
	if(displacement >= max_displacement)
	{
		fix_displacement(this_ckt);
	}

	/* Output Stage */
	string filename = directory + "circuit.pl";
	cout << "Output file is " << filename << endl;
	output_placement(this_ckt, filename.c_str());

	return 1;
}

